class Analyzer(metaclass=MetaAnalyzer):
    '''Analyzer基类。所有分析器都是此类的子类

    Analyzer实例在策略框架中运行，并为该策略提供分析。

    自动设置成员属性：

      - ``self.strategy``（提供对*strategy*和任何可从中访问的内容的访问）

      - ``self.datas[x]``提供对系统中存在的数据源数组的访问，也可以通过策略引用访问

      - ``self.data``，提供对``self.datas[0]``的访问

      - ``self.dataX`` -> ``self.datas[X]``

      - ``self.dataX_Y`` -> ``self.datas[X].lines[Y]``

      - ``self.dataX_name`` -> ``self.datas[X].name``

      - ``self.data_name`` -> ``self.datas[0].name``

      - ``self.data_Y`` -> ``self.datas[0].lines[Y]``

    这不是*Lines*对象，但方法和操作遵循相同的设计

      - ``__init__``在实例化和初始设置期间

      - ``start`` / ``stop``以表示操作的开始和结束

      - ``prenext`` / ``nextstart`` / ``next``方法系列，遵循相同方法在策略中的调用

      - ``notify_trade`` / ``notify_order`` / ``notify_cashvalue`` /
        ``notify_fund``，接收与策略的等效方法相同的通知

    操作模式是开放的，没有任何模式是首选。因此，可以使用“next”调用生成分析，在“stop”期间结束操作，甚至使用单个方法如“notify_trade”生成分析

    重要的是要覆盖“get_analysis”以返回包含分析结果的*dict-like*对象（实际格式取决于实现）

    '''

    def __len__(self):
        '''支持在分析器上调用“len”以实际返回策略的当前长度'''

    def notify_cashvalue(self, cash, value):
        '''在每个下一个周期之前接收现金/价值通知'''

    def notify_fund(self, cash, value, fundvalue, shares):
        '''接收当前现金、价值、基金价值和基金份额'''

    def notify_order(self, order):
        '''在每个下一个周期之前接收订单通知'''

    def notify_trade(self, trade):
        '''在每个下一个周期之前接收交易通知'''

    def next(self):
        '''在达到策略的最小周期后，为每个下一个调用策略调用一次'''

    def prenext(self):
        '''在达到策略的最小周期之前，为每个prenext调用策略调用一次

        分析器的默认行为是调用“next”
        '''

    def nextstart(self):
        '''在第一次达到最小周期时，为nextstart调用策略调用一次'''

    def start(self):
        '''调用以指示操作的开始，使分析器有时间设置所需的内容'''

    def stop(self):
        '''调用以指示操作的结束，使分析器有时间关闭所需的内容'''

    def create_analysis(self):
        '''旨在被子类覆盖。有机会创建保存分析的结构。

        默认行为是创建一个名为“rets”的“OrderedDict”
        '''

    def get_analysis(self):
        '''返回一个*dict-like*对象，其中包含分析结果

        字典中分析结果的键和格式取决于实现。

        甚至不强制要求结果是*dict-like对象*，只是约定

        默认实现返回默认的OrderedDict“rets”，该OrderedDict由默认的“create_analysis”方法创建

        '''

    def print(self, *args, **kwargs):
        '''通过标准的“Writerfile”对象打印由“get_analysis”返回的结果，默认情况下将其写入标准输出'''

    def pprint(self, *args, **kwargs):
        '''使用漂亮的打印Python模块（*pprint*）打印由“get_analysis”返回的结果'''


class AnnualReturn(Analyzer):
    '''
    此分析器通过查看年初和年末来计算年度回报率

    参数:

      - (None)

    成员属性:

      - ``rets``: 计算出的年度回报率列表

      - ``ret``: 字典（键：年份）的年度回报率

    **get_analysis**:

      - 返回年度回报率的字典（键：年份）
    '''


class Calmar(bt.TimeFrameAnalyzerBase):
    '''此分析器计算CalmarRatio
    时间框架可以与基础数据中使用的时间框架不同
    参数:

      - ``timeframe`` (默认值: ``None``)
        如果为``None``，则使用系统中第一个数据的``timeframe``

        传递``TimeFrame.NoTimeFrame``以考虑没有时间限制的整个数据集

      - ``compression`` (默认值: ``None``)

        仅用于子日时间框架，例如通过指定“TimeFrame.Minutes”和60来在小时时间框架上工作

        如果为``None``，则使用系统的第一个数据的压缩

      - *None*

      - ``fund`` (默认值: ``None``)

        如果为``None``，则会自动检测经纪人的实际模式（fundmode-True/False），以决定收益是否基于总净资产价值或基金价值。请参见经纪人文档中的``set_fundmode``

        将其设置为``True``或``False``以获得特定行为

    参见:

      - https://en.wikipedia.org/wiki/Calmar_ratio

    方法:
      - ``get_analysis``

        返回一个OrderedDict，其中包含时间段的键和相应的滚动Calmar比率

    属性:
      - ``calmar`` 最新计算的calmar比率
    '''


class DrawDown(bt.Analyzer):
    '''此分析器计算交易系统的回撤统计数据，例如以百分比和美元计算的回撤值，以及以百分比和美元计算的最大回撤值，回撤长度和最大回撤长度

    参数:

      - ``fund`` (默认值: ``None``)

        如果为``None``，则会自动检测经纪人的实际模式（fundmode-True/False），以决定收益是否基于总净资产价值或基金价值。请参见经纪人文档中的``set_fundmode``

        将其设置为``True``或``False``以获得特定行为

    方法:

      - ``get_analysis``

        返回一个字典（支持.符号和子字典），其中包含回撤统计数据作为值，可用以下键/属性：

        - ``drawdown`` - 以0.xx%计算的回撤值
        - ``moneydown`` - 以货币单位计算的回撤值
        - ``len`` - 回撤长度

        - ``max.drawdown`` - 以0.xx%计算的最大回撤值
        - ``max.moneydown`` - 以货币单位计算的最大回撤值
        - ``max.len`` - 最大回撤长度
    '''


class TimeDrawDown(bt.TimeFrameAnalyzerBase):
    '''此分析器计算所选时间框架上的交易系统回撤，该时间框架可以与基础数据中使用的时间框架不同

    参数:

      - ``timeframe`` (默认值: ``None``)
        如果为``None``，则使用系统中第一个数据的``timeframe``

        传递``TimeFrame.NoTimeFrame``以考虑没有时间限制的整个数据集

      - ``compression`` (默认值: ``None``)

        仅用于子日时间框架，例如通过指定“TimeFrame.Minutes”和60来在小时时间框架上工作

        如果为``None``，则使用系统的第一个数据的压缩

      - *None*

      - ``fund`` (默认值: ``None``)

        如果为``None``，则会自动检测经纪人的实际模式（fundmode-True/False），以决定收益是否基于总净资产价值或基金价值。请参见经纪人文档中的``set_fundmode``

        将其设置为``True``或``False``以获得特定行为

    方法:

      - ``get_analysis``

        返回一个字典（支持.符号和子字典），其中包含回撤统计数据作为值，可用以下键/属性：

        - ``drawdown`` - 以0.xx%计算的回撤值
        - ``maxdrawdown`` - 以货币单位计算的回撤值
        - ``maxdrawdownperiod`` - 回撤长度

      - 这些在运行期间作为属性可用
        - ``dd``
        - ``maxdd``
        - ``maxddlen``
    '''


class GrossLeverage(bt.Analyzer):
    '''此分析器按时间框架计算当前策略的总杠杆率

    参数:

      - ``fund`` (默认值: ``None``)

        如果为``None``，则会自动检测经纪人的实际模式（fundmode-True/False），以决定收益是否基于总净资产价值或基金价值。请参见经纪人文档中的``set_fundmode``

        将其设置为``True``或``False``以获得特定行为

    方法:

      - ``get_analysis``

        返回一个字典，其中包含以时间点为键，以总杠杆率为值的收益率
    '''


class LogReturnsRolling(bt.TimeFrameAnalyzerBase):
    '''该分析器计算给定时间框架和压缩的滚动收益率

    参数:

      - ``timeframe`` (默认值: ``None``)
        如果为``None``，则使用系统中第一个数据的``timeframe``

        传递``TimeFrame.NoTimeFrame``以考虑没有时间限制的整个数据集

      - ``compression`` (默认值: ``None``)

        仅用于子日时间框架，例如通过指定“TimeFrame.Minutes”和60来在小时时间框架上工作

        如果为``None``，则使用系统的第一个数据的压缩

      - ``data`` (默认值: ``None``)

        跟踪参考资产而不是投资组合价值。

        .. 注意:: 必须使用``addata``，``resampledata``或``replaydata``将此数据添加到``cerebro``实例中

      - ``firstopen`` (默认值: ``True``)

        当跟踪``data``的收益率时，当跨越时间框架边界时，例如``Years``，将执行以下操作：

          - 上一年的最后一个“close”用作参考价格，以查看当前年份的收益率

        问题在于第一次计算，因为数据没有先前的收盘价。因此，当此参数为``True``时，将使用*开盘*价格进行第一次计算。

        这需要数据源具有“open”价格（对于“close”，将使用标准[0]符号，而不参考价格）

        否则将使用初始收盘价。

      - ``fund`` (默认值: ``None``)

        如果为``None``，则会自动检测经纪人的实际模式（fundmode-True/False），以决定收益是否基于总净资产价值或基金价值。请参见经纪人文档中的``set_fundmode``

        将其设置为``True``或``False``以获得特定行为

    方法:

      - ``get_analysis``

        返回一个字典，其中包含收益率作为值，日期时间点作为键
    '''


class PeriodStats(bt.Analyzer):
    '''计算给定时间框架的基本统计信息

    参数:

      - ``timeframe`` (默认值: ``Years``)
        如果为``None``，则使用系统中第一个数据的``timeframe``

        传递``TimeFrame.NoTimeFrame``以考虑没有时间限制的整个数据集

      - ``compression`` (默认值: ``1``)

        仅用于子日时间框架，例如通过指定“TimeFrame.Minutes”和60来在小时时间框架上工作

        如果为``None``，则使用系统的第一个数据的压缩

      - ``fund`` (默认值: ``None``)

        如果为``None``，则会自动检测经纪人的实际模式（fundmode-True/False），以决定收益是否基于总净资产价值或基金价值。请参见经纪人文档中的``set_fundmode``

        将其设置为``True``或``False``以获得特定行为

    ``get_analysis`` 返回一个字典，其中包含以下键：

      - ``average`` - 平均值
      - ``stddev`` - 标准差
      - ``positive`` - 正收益期数
      - ``negative`` - 负收益期数
      - ``nochange`` - 无变化期数
      - ``best`` - 最佳收益期数
      - ``worst`` - 最差收益期数

    如果将参数``zeroispos``设置为``True``，则无变化期将被视为正收益期
    '''


class PositionsValue(bt.Analyzer):
    '''该分析器报告当前数据集的持仓价值

    参数:

      - timeframe (默认值: ``None``)
        如果为``None``，则使用系统中第一个数据的``timeframe``

      - compression (默认值: ``None``)

        仅用于子日时间框架，例如通过指定“TimeFrame.Minutes”和60来在小时时间框架上工作

        如果为``None``，则使用系统的第一个数据的压缩

      - headers (默认值: ``False``)

        在持有结果的字典中添加一个初始键，用于存储数据的名称（键为'Datetime'）

      - cash (默认值: ``False``)

        将实际现金作为额外的持仓（名称为'cash'）

    方法:

      - ``get_analysis``

        返回一个字典，其中包含持仓价值作为值，日期时间点作为键
    '''


class PyFolio(bt.Analyzer):
    '''该分析器使用4个子分析器收集数据并将其转换为与``pyfolio``兼容的数据集

    子分析器

      - ``TimeReturn``

        用于计算全局投资组合价值的收益率

      - ``PositionsValue``

        用于计算每个数据的持仓价值。它将``headers``和``cash``参数设置为``True``

      - ``Transactions``

        用于记录每个数据的每笔交易（大小、价格、价值）。将``headers``参数设置为``True``

      - ``GrossLeverage``

        跟踪总杠杆率（策略投资了多少资金）

    参数:
      这些参数会透明地传递给子分析器

      - timeframe（默认值：``bt.TimeFrame.Days``）

        如果为``None``，则使用系统中第一个数据的时间框架

      - compression（默认值：``1``）

        如果为``None``，则使用系统中第一个数据的压缩

    ``timeframe``和``compression``都遵循``pyfolio``的默认行为，即使用*每日*数据并将其上采样以获得年度收益率等值。

    方法:

      - ``get_analysis``

        返回一个字典，其中包含收益率作为值，日期时间点作为键
    '''


class Returns(TimeFrameAnalyzerBase):
    '''使用对数方法计算的总收益率、平均收益率、复合收益率和年化收益率

    参见：

      - https://www.crystalbull.com/sharpe-ratio-better-with-log-returns/

    参数:

      - ``timeframe`` (默认值: ``None``)

        如果为``None``，则使用系统中第一个数据的``timeframe``

        传递``TimeFrame.NoTimeFrame``以考虑没有时间限制的整个数据集

      - ``compression`` (默认值: ``None``)

        仅用于子日时间框架，例如通过指定“TimeFrame.Minutes”和60来在小时时间框架上工作

        如果为``None``，则使用系统的第一个数据的压缩

      - ``tann`` (默认值: ``None``)

        用于年化（标准化）的周期数

        分别为：

          - ``days: 252``
          - ``weeks: 52``
          - ``months: 12``
          - ``years: 1``

      - ``fund`` (默认值: ``None``)

        如果为``None``，则会自动检测经纪人的实际模式（fundmode-True/False），以决定收益是否基于总净资产价值或基金价值。请参见经纪人文档中的``set_fundmode``

        将其设置为``True``或``False``以获得特定行为

    方法:

      - ``get_analysis``

        返回一个字典，其中包含收益率作为值，日期时间点作为键

        返回的字典包含以下键：

          - ``rtot``: 总复合收益率
          - ``ravg``: 整个时间段（时间框架特定）的平均收益率
          - ``rnorm``: 年化/标准化收益率
          - ``rnorm100``: 以100%表示的年化/标准化收益率

    '''


class SharpeRatio(Analyzer):
    '''该分析器使用风险无关资产（即利率）计算策略的夏普比率

    参见：

      - https://en.wikipedia.org/wiki/Sharpe_ratio

    参数：

      - ``timeframe``: (默认值: ``TimeFrame.Years``)

      - ``compression`` (默认值: ``1``)

        仅用于子日时间框架，例如通过指定“TimeFrame.Minutes”和60来在小时时间框架上工作

      - ``riskfreerate`` (默认值: 0.01 -> 1%)

        以年度为单位表示（见下面的``convertrate``）

      - ``convertrate`` (默认值: ``True``)

        将``riskfreerate``从年度转换为月度、周度或日度利率。不支持子日转换

      - ``factor`` (默认值: ``None``)

        如果为``None``，则从预定义表中选择从*年度*到所选时间框架的无风险利率的转换因子

          Days: 252, Weeks: 52, Months: 12, Years: 1

        否则将使用指定的值

      - ``annualize`` (默认值: ``False``)

        如果``convertrate``为``True``，则*SharpeRatio*将以所选的``timeframe``形式呈现。

        在大多数情况下，SharpeRatio以年化形式呈现。将``riskfreerate``从年度转换为月度、周度或日度利率。不支持子日转换

      - ``stddev_sample`` (默认值: ``False``)

        如果将其设置为``True``，则将通过将均值的分母减少1来计算*标准偏差*。当计算*标准偏差*时，如果认为没有使用所有样本，则使用此选项。这称为*Bessels'校正*

      - ``daysfactor`` (默认值: ``None``)

        ``factor``的旧名称。如果将其设置为除``None``以外的任何值，并且``timeframe``为``TimeFrame.Days``，则假定这是旧代码，并使用该值

      - ``legacyannual`` (默认值: ``False``)

        使用``AnnualReturn``返回分析器，正如名称所示，仅适用于年份

      - ``fund`` (默认值: ``None``)

        如果为``None``，则会自动检测经纪人的实际模式（fundmode-True/False），以决定收益是否基于总净资产价值或基金价值。请参见经纪人文档中的``set_fundmode``

        将其设置为``True``或``False``以获得特定行为

    方法：

      - get_analysis

        返回一个字典，其中包含键“sharperatio”，其值为夏普比率

    '''


class SQN(Analyzer):
    '''SQN或系统质量数。由Van K. Tharp定义，用于分类交易系统。

      - 1.6 - 1.9 低于平均水平
      - 2.0 - 2.4 平均水平
      - 2.5 - 2.9 良好
      - 3.0 - 5.0 优秀
      - 5.1 - 6.9 极好
      - 7.0 -     圣杯？

    公式：

      - SquareRoot(NumberTrades) * Average(TradesProfit) / StdDev(TradesProfit)

    当交易次数>=30时，sqn值应被视为可靠。

    方法:

      - get_analysis

        返回一个字典，其中包含键“sqn”和“trades”（考虑的交易次数）

    '''

    def create_analysis(self):
        '''替换默认实现以实例化AutoOrdereDict而不是OrderedDict'''


class TimeReturn(TimeFrameAnalyzerBase):
    '''该分析器通过查看时间框架的开始和结束来计算收益率

    参数:

      - ``timeframe`` (默认值: ``None``)
        如果为``None``，则使用系统中第一个数据的``timeframe``

        传递``TimeFrame.NoTimeFrame``以考虑没有时间限制的整个数据集

      - ``compression`` (默认值: ``None``)

        仅用于子日时间框架，例如通过指定“TimeFrame.Minutes”和60来在小时时间框架上工作

        如果为``None``，则使用系统中第一个数据的压缩

      - ``data`` (默认值: ``None``)

        跟踪参考资产而不是投资组合价值。

        .. 注意:: 必须使用``addata``、``resampledata``或``replaydata``将此数据添加到``cerebro``实例中

      - ``firstopen`` (默认值: ``True``)

        当跟踪``data``的收益率时，当跨越时间框架边界时，例如``Years``：

          - 上一年的最后一个``close``被用作参考价格，以查看当前年份的收益率

        问题在于第一次计算，因为数据没有前一个收盘价。因此，当此参数为``True``时，将使用*开盘*价格进行第一次计算。

        这需要数据源具有``open``价格（对于``close``，将使用标准[0]符号，而不参考价格）

        否则将使用初始收盘价。

      - ``fund`` (默认值: ``None``)

        如果为``None``，则会自动检测经纪人的实际模式（fundmode-True/False），以决定收益是否基于总净资产价值或基金价值。请参见经纪人文档中的``set_fundmode``

        将其设置为``True``或``False``以获得特定行为

    方法:

      - get_analysis

        返回一个字典，其中包含收益率作为值，日期时间点作为键

    '''


class TradeAnalyzer(Analyzer):
    '''
    提供已关闭交易的统计信息（也保留了未关闭交易的计数）

      - 总开/平仓交易

      - 连胜/连败当前/最长

      - 总盈亏/平均盈亏

      - 获胜/失败次数/总盈亏/平均盈亏/最大盈亏

      - 多头/空头次数/总盈亏/平均盈亏/最大盈亏

          - 获胜/失败次数/总盈亏/平均盈亏/最大盈亏

      - 持仓时间（市场中的条形图）

        - 总数/平均值/最大值/最小值

        - 获胜/失败总数/平均值/最大值/最小值

        - 多头/空头总数/平均值/最大值/最小值

          - 获胜/失败总数/平均值/最大值/最小值

    注意:

      该分析器使用“auto”dict来存储字段，这意味着如果没有执行交易，则不会生成统计信息。

      在这种情况下，由``get_analysis``返回的字典中将只有一个字段/子字段，即:

        - dictname['total']['total']，其值为0（该字段也可以使用点符号dictname.total.total访问）
    '''


class Transactions(bt.Analyzer):
    '''该分析器报告了系统中每个数据发生的交易

    它查看订单执行位以创建每个“next”周期中从0开始的“Position”。

    结果在下一个周期中用于记录交易

    参数:

      - headers (默认值: ``True``)

        向保存结果的字典添加一个初始键，其中包含数据的名称

        此分析器的模型旨在便于与“pyfolio”集成，标题名称取自用于它的样本::

          'date', 'amount', 'price', 'sid', 'symbol', 'value'

    方法:

      - get_analysis

        返回一个字典，其中包含收益率作为值，日期时间点作为键
    '''


class VWR(TimeFrameAnalyzerBase):
    '''变异性加权回报：对数回报更好的夏普比率

    别名:

      - VariabilityWeightedReturn

    参见:

      - https://www.crystalbull.com/sharpe-ratio-better-with-log-returns/

    参数:

      - ``timeframe`` (默认值: ``None``)
        如果为``None``，则报告整个回测期间的完整回报

        传递``TimeFrame.NoTimeFrame``以考虑没有时间限制的整个数据集

      - ``compression`` (默认值: ``None``)

        仅用于子日时间框架，例如通过指定“TimeFrame.Minutes”和60来在小时时间框架上工作

        如果为``None``，则使用系统中第一个数据的压缩

      - ``tann`` (默认值: ``None``)

        用于年化（标准化）平均回报的周期数。如果为``None``，则使用标准的``t``值，即：

          - ``days: 252``
          - ``weeks: 52``
          - ``months: 12``
          - ``years: 1``

      - ``tau`` (默认值: ``2.0``)

        计算因子（请参阅文献）

      - ``sdev_max`` (默认值: ``0.20``)

        最大标准差（请参阅文献）

      - ``fund`` (默认值: ``None``)

        如果为``None``，则会自动检测经纪人的实际模式（fundmode-True/False），以决定收益是否基于总净资产价值或基金价值。请参见经纪人文档中的``set_fundmode``

        将其设置为``True``或``False``以获得特定行为

    方法:

      - get_analysis

        返回一个字典，其中包含收益率作为值，日期时间点作为键

        返回的字典包含以下键:

          - ``vwr``: 变异性加权回报
    '''

